import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.Scanner;


public class Client {

	private int playerId;
	private GameStatus status;
	private ServerAPI stub;
//	private ServerInformation backUpServer;
	private ServerAPI backUpStub;
	
	
	
	public ServerAPI getBackUpStub() {
		return backUpStub;
	}

	public void setBackUpStub(ServerAPI backUpStub) {
		this.backUpStub = backUpStub;
		try {
			this.backUpStub.printIdentity(1, getPlayerId());
		} catch (RemoteException e) {

			System.out.println("Error in setBackUpStub");
		}
	}

	public Client(ServerAPI stub)
	{
		this.setStub(stub);
		
	}
		
	public Client()
	{
		
	}
	
	public int getPlayerId() {
		return playerId;
	}


	public GameStatus getStatus() {
		return status;
	}


	public void setPlayerId(int playerId) {
		this.playerId = playerId;
	}


	public void setStatus(GameStatus status) {
		this.status = status;
	}

	public ServerAPI getStub() {
		return stub;
	}


	public void setStub(ServerAPI stub) {
		this.stub = stub;
		try {
			this.stub.printIdentity(0, getPlayerId());
		} catch (RemoteException e) {
			System.out.println("Error in Client constructor");
		}

	}
	

	// To start the server
	public static void start(int port, String host, boolean mainServer, int myPort) {
		// TODO Auto-generated method stub

		try {
			Registry registry = null;
			
			if (port == -1)
			    registry = LocateRegistry.getRegistry(host);
			else
				registry = LocateRegistry.getRegistry(host, port);
		    ServerAPI stub = (ServerAPI) registry.lookup("ServerAPI0");
		    
		    // Initializing the client class
		    Client client = new Client(stub);
		    
		    // To connect to main server
		    client.startGame(mainServer, myPort);
		    // To play the game once connected to the main server
		    client.playGame();
		} catch (Exception e) {
		    System.err.println("Client exception in static start");
		}		
	}
	
	// Communicates with the server
	private Pair<Boolean, GameStatus> makeMove(char input) throws RemoteException
	{
		boolean moveMade = false;
		Pair<Boolean, GameStatus> result = null;
		while (!moveMade)
		{
	    	switch (input)
	    	{
	    		case 'N': result = stub.move(getPlayerId(), 1);
					if (result.getFirst())
						System.out.println("Client: Move was successful");
					else 
						System.out.println("Client: Move was not successful");
					result.getSecond().toString();
					moveMade = true;
					break;
		    	case 'S': result = stub.move(getPlayerId(), 2);
				    if (result.getFirst())
				    	System.out.println("Client: Move was successful");
				    else 
				    	System.out.println("Client: Move was not successful");
				    result.getSecond().toString();
					moveMade = true;
				    break;
			    case 'E': result = stub.move(getPlayerId(), 3);
				    if (result.getFirst())
				    	System.out.println("Client: Move was successful");
				    else 
				    	System.out.println("Client: Move was not successful");
				    result.getSecond().toString();
					moveMade = true;
				    break;
			    case 'W': result = stub.move(getPlayerId(), 4);
				    if (result.getFirst())
				    	System.out.println("Client: Move was successful");
				    else 
				    	System.out.println("Client: Move was not successful");
				    result.getSecond().toString();
					moveMade = true;
				    break;
			    case 'D': result = stub.move(getPlayerId(), 0);
				    if (result.getFirst())
				    	System.out.println("Client: Move was successful");
				    else 
				    	System.out.println("Client: Move was not successful");
				    result.getSecond().toString();
					moveMade = true;
				    break;
			    default: System.out.println("Client: Only allowed inputs are N,S,E,W and D");
			    	break;
	    	}
	    	if (!moveMade)
	    	{
	    		Scanner sc = new Scanner(System.in);
	    		String in = sc.next();
	    		input = in.charAt(0);
	    	}
		}
    	return result;
	}
	
	public void playGame()
	{
		Scanner sc = new Scanner(System.in);
		
		// Infinite loop
		while (true)
		{
			System.out.println("Client: Please enter your move (N,S,E,W,D)");
			// Getting input
			String inputStr = sc.next();
			char input = inputStr.charAt(0);
		    Pair <Boolean,GameStatus> result = null;
		    try
		    {
		    	result = makeMove(input); // Calling the makeMove function which calls the move function of the server
		    } 
		    catch (RemoteException e) 
		    {
		    	try
		    	{
		    		// If main has crashed, connect to back up and continue game
		    		System.out.println("Client: The main server has crashed. Changing to back up server");
		    		setStub(backUpStub);
		    		result = makeMove(input);
		    	}
		    	catch (Exception eee)
		    	{
		    		System.out.println("Client: Problem in getting a new back up server running");
		    	}
			}
		    status = result.getSecond();
		    if (status.getRemainingNoOfTreasures() == 0)
		    {
		    	// Game is over after the remaining treasures is 0
		    	System.out.println("Client: The remaining number of treasures is 0. Game over");
		    	System.exit(0);
		    }
		}
		
	}
	
	// Connect to the main server
	public void startGame(boolean mainServer, int myPort) throws RemoteException
	{
		Pair<Boolean, Integer> pair = stub.joinGame(mainServer);
		if (!pair.getFirst())
		{
			System.out.println("Client: Join game failed");
		
			System.exit(0);
			
		}
		
		// getting the player id from the paid and setting it in the client
		setPlayerId(pair.getSecond());
		System.out.println("Client: My id is "+getPlayerId());
		if (!mainServer)
		{
			Server obj = new Server(this, getPlayerId());
			Server.start(obj);
		}
		
		// Waitin for the 20 second period to start
		StartGameStatus sg = stub.waitToPlay(getPlayerId(), myPort);
		
		// Get the game status
		setStatus(sg.getGameStatus());
		
		// Connecting to the back up server
		try 
		{
			ServerInformation backUpServer = sg.getBackUpServer();
			Registry registry = null;
			String host = backUpServer.getHost();
			int port = backUpServer.getPort();
			String registryBindString = "ServerAPI"+backUpServer.getId();
			if (port == -1)
				registry = LocateRegistry.getRegistry(host);
			else
				registry = LocateRegistry.getRegistry(host, port);
			ServerAPI stub = (ServerAPI) registry.lookup(registryBindString);
			setBackUpStub(stub);
		} catch (Exception ee) {
			System.err.println("Client: Problems in settings back up server ");
		}		
		
		
		status.toString();		
	}
}
